package com.lpy.action;

import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.lpy.util.GotoUtil;
import org.jetbrains.annotations.NotNull;

/**
 * @author Lipengyu
 * @since 2021/11/13 22:12
 */
public class GoToDeclareAction extends AnAction {

    /**
     * 规则 Repository extends GenericJpaRepository<EntityName, xxx> => EntityName + .sftl
     * 根据规则跳转文件
     * @param anActionEvent 事件
     */
    @Override
    public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
        // 当前文件
        PsiFile psiFile = anActionEvent.getData(PlatformDataKeys.PSI_FILE);
        if (psiFile == null) {
            return;
        }
        // 获取当前 Project
        Project project = anActionEvent.getProject();
        if (project == null) {
            return;
        }
        // 当前 Module
        ProjectFileIndex fileIndex = ProjectFileIndex.getInstance(project);
        Module module = fileIndex.getModuleForFile(psiFile.getContainingFile().getVirtualFile());
        if (module == null) {
            return;
        }
        // 获取当前 Editor
        Editor editor = CommonDataKeys.EDITOR.getData(anActionEvent.getDataContext());
        if (editor == null) {
            return;
        }
        if (GotoUtil.isEntitySftl(psiFile)) {
            jumpEntityRepository(psiFile, project, module, editor);
        } else {
            jumpEntitySftl(anActionEvent, project, module);
        }
    }

    /**
     * 跳转到 Entity.sftl
     * @param anActionEvent 事件
     * @param project Project
     * @param module Module
     */
    private void jumpEntitySftl(@NotNull AnActionEvent anActionEvent, Project project, Module module) {
        PsiElement currentPsiElement = anActionEvent.getData(LangDataKeys.PSI_ELEMENT);
        if (currentPsiElement == null) {
            return;
        }
        if (GotoUtil.isJpaExtraMethod(currentPsiElement)) {
            PsiClass currentPsiClass = (PsiClass) currentPsiElement.getParent();
            String entityClassName = GotoUtil.getEntityClassName(currentPsiClass);
            if (entityClassName == null) {
                return;
            }
            String repositoryClassName = currentPsiClass.getName();
            if (GotoUtil.isBlank(repositoryClassName)) {
                return;
            }
            PsiMethod currentPsiMethod = (PsiMethod) currentPsiElement;
            String methodName = currentPsiMethod.getName();
            String sqlId = "-- " + methodName;
            // 根据名称查找映射文件
            PsiFile[] entitySftlPsiFiles = FilenameIndex.getFilesByName(project, entityClassName + ".sftl", GlobalSearchScope.moduleScope(module));
            for (PsiFile file : entitySftlPsiFiles) {
                if (GotoUtil.containsSqlId(file, methodName)) {
                    GotoUtil.doLocateSftl(project, currentPsiMethod.getName(), file);
                    return;
                }
                WriteCommandAction.runWriteCommandAction(project, () -> {
                    OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file.getVirtualFile());
                    // 打开文件
                    Editor sftlEditor = FileEditorManager.getInstance(project)
                            .openTextEditor(descriptor, true);
                    if (sftlEditor == null) {
                        return;
                    }
                    Document document = sftlEditor.getDocument();
                    if (document.getText().endsWith("\n")) {
                        document.insertString(file.getTextLength(), "\n" + sqlId + "\n");
                    } else {
                        document.insertString(file.getTextLength(), "\n\n" + sqlId + "\n");
                    }
                    // 跳转成功，结束该方法
                    GotoUtil.doLocateLast(project, file);
                });
            }
            // 如果没有找到，则创建新的sftl文件
            if (entitySftlPsiFiles.length == 0) {
                WriteCommandAction.runWriteCommandAction(project, () -> {
                    GotoUtil.createFileAndJump(project, module, entityClassName, sqlId);
                });
            }
        }
    }

    /**
     * 跳转到 EntityName + Repository.java
     * @param psiFile 当前文件
     * @param project Project
     * @param module Module
     * @param editor Editor
     */
    private void jumpEntityRepository(PsiFile psiFile, Project project, Module module, Editor editor) {
        int currentPositionOffset = editor.getCaretModel().getOffset();
        String fileName = psiFile.getName();
        String[] split = fileName.split("\\.");
        if (split.length == 0) {
            return;
        }
        PsiElement elementAt = psiFile.findElementAt(currentPositionOffset);
        if (elementAt instanceof PsiWhiteSpaceImpl) {
            elementAt = elementAt.getPrevSibling();
        }
        if (elementAt == null) {
            return;
        }
        String methodName = elementAt.getText();
        if (GotoUtil.isBlank(fileName) || GotoUtil.isBlank(methodName)) {
            return;
        }
        if (methodName.startsWith(GotoUtil.SFTL_SQL_ID_PREFIX)) {
            methodName = methodName.substring(3).trim();
        }
        // 规则 EntityName + Repository.java => EntityName + .sftl
        // 按照规则命名跳转
        @NotNull PsiFile[] foundFiles = FilenameIndex.getFilesByName(project, String.format("%s.java", split[0] + GotoUtil.REPOSITORY),
                GlobalSearchScope.moduleScope(module));
        boolean success;
        for (PsiFile t : foundFiles) {
            PsiIdentifier nameIdentifier = GotoUtil.getPsiIdentifier(methodName, (PsiJavaFile) t);
            if (nameIdentifier != null) {
                success = GotoUtil.doLocateMethod(project, t, nameIdentifier.getTextRange().getStartOffset());
            } else {
                success = GotoUtil.doLocate(project, methodName, t);
            }
            // 如果找到了，则结束该方法
            if (success) {
                return;
            }
        }
        // 未按照规则命名，查找全局
        @NotNull PsiMethod[] methodsByName = PsiShortNamesCache.getInstance(project).getMethodsByName(methodName, GlobalSearchScope.moduleScope(module));
        if (methodsByName.length == 0) {
            return;
        }
        for (PsiMethod psiMethod : methodsByName) {
            PsiClass containingClass = psiMethod.getContainingClass();
            if (containingClass != null && containingClass.getQualifiedName() != null) {
                String qualifiedName = containingClass.getQualifiedName();
                if (qualifiedName.contains(GotoUtil.REPOSITORY) && split[0].equals(GotoUtil.getEntityClassName(containingClass))) {
                    PsiFile containingFile = containingClass.getContainingFile();
                    // 如果找到了，则结束该方法
                    if (containingFile != null && GotoUtil.doLocateMethod(project, containingFile, psiMethod.getTextOffset())) {
                        return;
                    }
                }
            }
        }
    }
}
